home *** CD-ROM | disk | FTP | other *** search
/ Sprite 1984 - 1993 / Sprite 1984 - 1993.iso / src / machserver / 1.098 / proc / procExit.c < prev    next >
C/C++ Source or Header  |  1991-07-26  |  51KB  |  1,697 lines

  1. /*
  2.  * procExit.c --
  3.  *
  4.  *    Routines to terminate and detach processes, and to cause a 
  5.  *    process to wait for the termination of other processes.  This file
  6.  *    maintains a monitor to synchronize between exiting, detaching, and
  7.  *    waiting processes.  The monitor also synchronizes access to the
  8.  *    dead list.
  9.  *
  10.  * Copyright 1986, 1988 Regents of the University of California
  11.  * Permission to use, copy, modify, and distribute this
  12.  * software and its documentation for any purpose and without
  13.  * fee is hereby granted, provided that the above copyright
  14.  * notice appear in all copies.  The University of California
  15.  * makes no representations about the suitability of this
  16.  * software for any purpose.  It is provided "as is" without
  17.  * express or implied warranty.
  18.  *
  19.  *    Proc table fields managed by this monitor:
  20.  *
  21.  *        1) exitFlags is managed solely by this monitor.
  22.  *        2) When a process is about to exit the PROC_DYING flag is set
  23.  *           in the genFlags field.  Also PROC_NO_VM flag set before
  24.  *           freeing VM segments.
  25.  *        3) The only way a process can go to the exiting and dead states 
  26.  *           is through using routines in this file.
  27.  *
  28.  *    A process can be in one of several states:
  29.  *
  30.  *    PROC_READY:    It is ready to execute when a CPU becomes available.
  31.  *            The PCB is attached to the Ready list.
  32.  *    PROC_RUNNING:    It is currently executing on a CPU.
  33.  *            The PCB is in the list of running processes.
  34.  *    PROC_WAITING:    It is waiting for an event to occur. 
  35.  *            The PCB is attached to an event-specific list of 
  36.  *            waiting processes.
  37.  *    PROC_EXITING:    It has finished executing but the PCB is kept around
  38.  *            until the parent waits for it via Proc_Wait or dies
  39.  *            via Proc_Exit.
  40.  *    PROC_DEAD:    It has been waited on and the PCB is attached to 
  41.  *            the Dead list.
  42.  *    PROC_SUSPENDED  It is suspended from executing.
  43.  *    PROC_UNUSED:    There is no process using this PCB entry.
  44.  *
  45.  *    In addition, the process may have the following attributes:
  46.  *
  47.  *    PROC_DETACHED:    It is detached from its parent.
  48.  *    PROC_WAITED_ON:    It is detached from its parent and its parent
  49.  *            knows about it. This attribute implies PROC_DETACHED
  50.  *            has been set.
  51.  *    PROC_SUSPEND_STATUS:
  52.  *            It is suspended and its parent has not waited on it
  53.  *            yet.  In this case it isn't detached.
  54.  *    PROC_RESUME_STATUS:
  55.  *            It has been resumed and its parent has not waited on
  56.  *            it yet.  In this case it isn't detached.
  57.  *
  58.  *    These attributes are set independently of the process states.
  59.  *
  60.  *    The routines in this file deal with transitions from the
  61.  *    RUNNING state to the EXITING and DEAD states and methods to 
  62.  *    detach a process.
  63.  *
  64.  *  State and Attribute Transitions:
  65.  *    The following tables show how a process changes attributes and states.
  66.  *
  67.  *
  68.  *   Legend:
  69.  *    ATTRIBUTE1 -> ATTRIBUTE2:
  70.  *    ---------------------------------------------------------------------
  71.  *      who        "routine it called to change attribute"    comments
  72.  *
  73.  *
  74.  *
  75.  *    Attached  -> Detached
  76.  *    ---------------------------------------------------------------------
  77.  *     current process    Proc_Detach
  78.  *
  79.  *    Detached -> Detached and Waited on
  80.  *    ---------------------------------------------------------------------
  81.  *     parent         Proc_Wait    WAITED_ON attribute set when
  82.  *                        parent finds child is detached.
  83.  *
  84.  *    Attached or Detached -> Detached and Waited on
  85.  *    ---------------------------------------------------------------------
  86.  *     parent            Proc_ExitInt    parent exiting, child detached.
  87.  *
  88.  *
  89.  *
  90.  *
  91.  *   Legend:
  92.  *    STATE1 -> STATE2:    (attributes before transition)
  93.  *    ---------------------------------------------------------------------
  94.  *      who        "routine it called to change state"     comments
  95.  *
  96.  *
  97.  *    RUNNING -> EXITING:    (attached or detached but not waited on)
  98.  *    RUNNING -> DEAD:    (detached and waited on)
  99.  *    ---------------------------------------------------------------------
  100.  *     current process    Proc_Exit    normal termination.
  101.  *     kernel            Proc_ExitInt    invalid process state found or
  102.  *                        process got a signal
  103.  *
  104.  *    EXITING -> DEAD:    (attached or detached or detached and waited on)
  105.  *    ---------------------------------------------------------------------
  106.  *     last family member to exit    Proc_ExitInt    
  107.  *     parent            Proc_Wait    parent waiting for child to exit
  108.  *     parent            Proc_ExitInt    parent exiting but did not 
  109.  *                        wait on child.
  110.  *
  111.  *    DEAD -> UNUSED:
  112.  *    ---------------------------------------------------------------------
  113.  *      The Reaper        Proc_Reaper     kernel process to clean the
  114.  *                        dead list. 
  115.  */
  116.  
  117. #ifndef lint
  118. static char rcsid[] = "$Header: /sprite/src/kernel/proc/RCS/procExit.c,v 9.19 91/07/26 16:59:47 shirriff Exp $ SPRITE (Berkeley)";
  119. #endif /* not lint */
  120.  
  121. #include <sprite.h>
  122. #include <mach.h>
  123. #include <status.h>
  124. #include <proc.h>
  125. #include <procInt.h>
  126. #include <procMigrate.h>
  127. #include <migrate.h>
  128. #include <sync.h>
  129. #include <sched.h>
  130. #include <list.h>
  131. #include <sys.h>
  132. #include <vm.h>
  133. #include <prof.h>
  134. #include <dbg.h>
  135. #include <stdlib.h>
  136. #include <rpc.h>
  137. #include <sig.h>
  138. #include <stdio.h>
  139. #include <vmMach.h>
  140. #include <recov.h>
  141.  
  142. static    Sync_Lock    exitLock = Sync_LockInitStatic("Proc:exitLock"); 
  143. #define    LOCKPTR &exitLock
  144.  
  145. static     INTERNAL ReturnStatus FindExitingChild _ARGS_((
  146.                     Proc_ControlBlock *parentProcPtr,
  147.                     Boolean returnSuspend, int numPids,
  148.                     Proc_PID *pidArray, 
  149.                     ProcChildInfo *infoPtr));
  150. static     INTERNAL void WakeupMigratedParent _ARGS_((Proc_PID pid));
  151. static     void     SendSigChild _ARGS_((ClientData data, 
  152.             Proc_CallInfo *callInfoPtr));
  153. static     Proc_State    ExitProcessInt _ARGS_((
  154.                 Proc_ControlBlock *exitProcPtr,
  155.                 Boolean    migrated, Boolean contextSwitch));
  156.  
  157. /*
  158.  * Shared memory.
  159.  */
  160. extern int vmShmDebug;
  161. #ifndef lint
  162. #define dprintf if (vmShmDebug) printf
  163. #else /* lint */
  164. #define dprintf printf
  165. #endif /* lint */
  166.  
  167. /*
  168.  * SIGNAL_PARENT
  169.  *
  170.  * Macro to send a SIG_CHILD message to the parent.
  171.  */
  172. #define SIGNAL_PARENT(parentProcPtr, funcName) \
  173.     if ((parentProcPtr)->genFlags & PROC_USER) { \
  174.     ReturnStatus    status; \
  175.     Proc_Lock(parentProcPtr); \
  176.     status = Sig_SendProc(parentProcPtr, SIG_CHILD, 0, (Address)0); \
  177.     Proc_Unlock(parentProcPtr); \
  178.     if (status != SUCCESS) { \
  179.         printf("Warning: %s: Could not signal parent, status<%x>", \
  180.                 funcName, status); \
  181.     } \
  182.     }
  183.  
  184.  
  185. /*
  186.  *----------------------------------------------------------------------
  187.  *
  188.  * Proc_Exit --
  189.  *
  190.  *    The current process has decided to end it all voluntarily.
  191.  *    Call an internal procedure to do the work.
  192.  *
  193.  * Results:
  194.  *    None.  This routine should NOT return!
  195.  *
  196.  * Side effects:
  197.  *    None.
  198.  *
  199.  *----------------------------------------------------------------------
  200.  */
  201.  
  202. void
  203. Proc_Exit(status)
  204.     int    status;        /* Exit status from caller. */
  205. {
  206.     Proc_ExitInt(PROC_TERM_EXITED, status, 0);
  207.  
  208.     /*
  209.      *  Proc_ExitInt should never return.
  210.      */
  211. }
  212.  
  213.  
  214. /*
  215.  *----------------------------------------------------------------------
  216.  *
  217.  * Proc_ExitInt --
  218.  *
  219.  *    Internal routine to handle the termination of a process.  It
  220.  *    determines the process that is exiting and then calls
  221.  *    ProcExitProcess to do the work. This routine does NOT return because
  222.  *    a context switch is performed.  If the process is foreign,
  223.  *    ProcRemoteExit is called to handle cleanup on the home node
  224.  *    of the process, then ProcExitProcess is called.
  225.  *
  226.  * Results:
  227.  *    None.
  228.  *
  229.  * Side effects:
  230.  *    None.
  231.  *
  232.  *----------------------------------------------------------------------
  233.  */
  234.  
  235. void
  236. Proc_ExitInt(reason, status, code)
  237.     int reason;    /* Why the process is dying: EXITED, SIGNALED, DESTROYED  */
  238.     int    status;    /* Exit status or signal # or destroy status */
  239.     int code;    /* Signal sub-status */
  240. {
  241.     register Proc_ControlBlock     *curProcPtr;
  242.  
  243.     curProcPtr = Proc_GetActualProc();
  244.     if (curProcPtr == (Proc_ControlBlock *) NIL) {
  245.     panic("Proc_ExitInt: bad procPtr.\n");
  246.     }
  247.  
  248.     if (curProcPtr->genFlags & PROC_FOREIGN) {
  249.     ProcRemoteExit(curProcPtr, reason, status, code);
  250.     }
  251.     if (curProcPtr->Prof_Scale != 0) {
  252.     Prof_Disable(curProcPtr);
  253.     }
  254.     if (curProcPtr->genFlags & PROC_DEBUGGED) {
  255.     /*
  256.      * If a process is being debugged then force it onto the debug
  257.      * list before allowing it to exit.
  258.      */
  259.     Proc_SuspendProcess(curProcPtr, TRUE, reason, status, code);
  260.     }
  261.  
  262.     if (sys_ErrorShutdown) {
  263.     /*
  264.      * Are shutting down the system because of an error.  In this case
  265.      * don't close anything down because we want to leave as much state
  266.      * around as possible.
  267.      */
  268.     Sched_ContextSwitch(PROC_DEAD);
  269.     }
  270.     ProcExitProcess(curProcPtr, reason, status, code, TRUE);
  271.  
  272.     panic("Proc_ExitInt: Exiting process still alive!!!\n");
  273. }
  274.  
  275.  
  276. /*
  277.  *----------------------------------------------------------------------
  278.  *
  279.  * ExitProcessInt --
  280.  *
  281.  *    Do monitor level exit stuff for the process.
  282.  *
  283.  * Results:
  284.  *    None.
  285.  *
  286.  * Side effects:
  287.  *    None.
  288.  *
  289.  *----------------------------------------------------------------------
  290.  */
  291.  
  292. ENTRY static Proc_State
  293. ExitProcessInt(exitProcPtr, migrated, contextSwitch) 
  294.     register Proc_ControlBlock    *exitProcPtr;    /* The exiting process. */
  295.     Boolean            migrated;    /* TRUE => foreign process. */
  296.     Boolean            contextSwitch;    /* TRUE => context switch. */
  297. {
  298.     register    Proc_ControlBlock    *procPtr;
  299.     Proc_State                newState = PROC_UNUSED;
  300.     register Proc_PCBLink         *procLinkPtr;
  301.     Timer_Ticks                 ticks;
  302.  
  303.     LOCK_MONITOR;
  304.  
  305.  
  306.     Proc_Lock(exitProcPtr);
  307.  
  308.     exitProcPtr->genFlags |= PROC_DYING;
  309.  
  310.     if (exitProcPtr->genFlags & PROC_MIG_PENDING) {
  311.     /*
  312.      * Someone is waiting for this guy to migrate.  Let them know that
  313.      * the process is dying.
  314.      */
  315.     exitProcPtr->genFlags &= ~PROC_MIG_PENDING;
  316.     ProcMigWakeupWaiters();
  317.     }
  318.  
  319.     /*
  320.      *  If the parent is still around, add the user and kernel cpu usage
  321.      *  of this process to the parent's summary of children.
  322.      *  If we're detached, don't give this stuff to the parent
  323.      *  (it might not exist.)  Keep track of global usage if we're local.
  324.      */
  325.  
  326.     if (!(exitProcPtr->genFlags & PROC_FOREIGN)) {
  327.     if (!(exitProcPtr->exitFlags & PROC_DETACHED)) {
  328.         register Proc_ControlBlock     *parentProcPtr;
  329.  
  330.         parentProcPtr = Proc_GetPCB(exitProcPtr->parentID);
  331.         if (parentProcPtr != (Proc_ControlBlock *) NIL) {
  332.         Timer_AddTicks(exitProcPtr->kernelCpuUsage.ticks, 
  333.                    parentProcPtr->childKernelCpuUsage.ticks, 
  334.                    &(parentProcPtr->childKernelCpuUsage.ticks));
  335.         Timer_AddTicks(exitProcPtr->childKernelCpuUsage.ticks, 
  336.                    parentProcPtr->childKernelCpuUsage.ticks, 
  337.                    &(parentProcPtr->childKernelCpuUsage.ticks));
  338.         Timer_AddTicks(exitProcPtr->userCpuUsage.ticks, 
  339.                    parentProcPtr->childUserCpuUsage.ticks, 
  340.                    &(parentProcPtr->childUserCpuUsage.ticks));
  341.         Timer_AddTicks(exitProcPtr->childUserCpuUsage.ticks, 
  342.                    parentProcPtr->childUserCpuUsage.ticks, 
  343.                    &(parentProcPtr->childUserCpuUsage.ticks));
  344.         }
  345.     }
  346. #ifndef CLEAN
  347.     Timer_AddTicks(exitProcPtr->kernelCpuUsage.ticks,
  348.             exitProcPtr->userCpuUsage.ticks, &ticks);
  349.     ProcRecordUsage(ticks, PROC_MIG_USAGE_TOTAL_CPU);
  350.     /*
  351.      * Record usage for just the amount of work performed after the
  352.      * first eviction.
  353.      */
  354.     if (exitProcPtr->migFlags & PROC_WAS_EVICTED) {
  355.         if (proc_MigDebugLevel > 4) {
  356.         printf("ExitProcessInt: process %x was evicted.  Used %d ticks before eviction, %d total.\n",
  357.                exitProcPtr->processID,
  358.                exitProcPtr->preEvictionUsage.ticks,
  359.                ticks);
  360.         }
  361.         Timer_SubtractTicks(ticks, exitProcPtr->preEvictionUsage.ticks,
  362.                 &ticks);
  363.         ProcRecordUsage(ticks, PROC_MIG_USAGE_POST_EVICTION);
  364.         exitProcPtr->migFlags &= ~PROC_WAS_EVICTED;
  365.     }
  366. #endif /* CLEAN */
  367.     }
  368.  
  369.     
  370.     /*
  371.      * Make sure there are no lingering interval timer callbacks associated
  372.      * with this process.
  373.      *
  374.      *  Go through the list of children of the current process to 
  375.      *  make them orphans. When the children exit, this will typically
  376.      *  cause them to go on the dead list directly.
  377.      */
  378.  
  379.     if (!migrated) {
  380.     ProcDeleteTimers(exitProcPtr);
  381.     while (!List_IsEmpty(exitProcPtr->childList)) {
  382.         procLinkPtr = (Proc_PCBLink *) List_First(exitProcPtr->childList);
  383.         procPtr = procLinkPtr->procPtr;
  384.         List_Remove((List_Links *) procLinkPtr);
  385.         if (procPtr->state == PROC_EXITING) {
  386.         /*
  387.          * The child is exiting waiting for us to wait for it.
  388.          */
  389.         procPtr->state = PROC_DEAD;
  390.         Proc_CallFunc(Proc_Reaper, (ClientData) procPtr, 0);
  391.         } else {
  392.         /*
  393.          * Detach the child so when it exits, it will be
  394.          * put on the dead list automatically.
  395.          */
  396.         procPtr->exitFlags = PROC_DETACHED | PROC_WAITED_ON;
  397.         }
  398.     }
  399.     }
  400.  
  401.     /*
  402.      * If the debugger is waiting for this process to return to the debug
  403.      * state wake it up so that it will realize that the process is dead.
  404.      */
  405.  
  406.     if (exitProcPtr->genFlags & PROC_DEBUG_WAIT) {
  407.     ProcDebugWakeup();
  408.     }
  409.  
  410.     /*
  411.      * If the process is still waiting on an event, this is an error.
  412.      * [For now, flag this error only for foreign processes in case this
  413.      * isn't really an error after all.]
  414.      */
  415.     if (migrated && (exitProcPtr->event != NIL)) {
  416.     if (proc_MigDebugLevel > 0) {
  417.         panic(
  418.         "ExitProcessInt: exiting process still waiting on event %x.\n",
  419.         exitProcPtr->event);
  420.     } else {
  421.         printf(
  422.           "%s ExitProcessInt: exiting process still waiting on event %x.\n",
  423.           "Warning:", exitProcPtr->event);
  424.     }
  425.     }
  426.  
  427.     /*
  428.      * If the current process is detached and waited on (i.e. an orphan) then
  429.      * one of two things happen.  If the process is a family head and its list
  430.      * of family members is not empty then the process is put onto the exiting
  431.      * list.  Otherwise the process is put onto the dead list since its 
  432.      * parent has already waited for it.
  433.      */
  434.  
  435.     if (((exitProcPtr->exitFlags & PROC_DETACHED) &&
  436.         (exitProcPtr->exitFlags & PROC_WAITED_ON)) || migrated) {
  437.     newState = PROC_DEAD;
  438.     Proc_CallFunc(Proc_Reaper,  (ClientData) exitProcPtr, 0);
  439.     } else {
  440.     Proc_ControlBlock     *parentProcPtr;
  441.  
  442. #ifdef DEBUG_PARENT_PID
  443.     int hostID;
  444.     
  445.     hostID = Proc_GetHostID(exitProcPtr->parentID);
  446.     if (hostID != rpc_SpriteID && hostID != 0) {
  447.         panic("ExitProcessInt: parent process (%x) is on wrong host.\n",
  448.           exitProcPtr->parentID);
  449.         goto done;
  450.     }
  451. #endif DEBUG_PARENT_PID
  452.     parentProcPtr = Proc_GetPCB(exitProcPtr->parentID);
  453.     if (parentProcPtr == (Proc_ControlBlock *) NIL) {
  454.         panic("ExitProcessInt: no parent process (pid == %x)\n",
  455.           exitProcPtr->parentID);
  456.         goto done;
  457.     }
  458.     if (parentProcPtr->state != PROC_MIGRATED) {
  459.         Sync_Broadcast(&parentProcPtr->waitCondition);
  460. #ifdef notdef
  461.         SIGNAL_PARENT(parentProcPtr, "ExitProcessInt");
  462. #endif
  463.     } else {
  464.         WakeupMigratedParent(parentProcPtr->processID);
  465.     }
  466.     /*
  467.      * Signal the parent later on, when not holding the exit monitor
  468.      * lock.
  469.      */
  470.     Proc_CallFunc(SendSigChild, (ClientData)exitProcPtr->parentID, 0);
  471.  
  472.  
  473.     newState = PROC_EXITING;
  474.     }
  475. done:
  476.     if (contextSwitch) {
  477.     Proc_Unlock(exitProcPtr);
  478.     UNLOCK_MONITOR_AND_SWITCH(newState);
  479.     panic("ExitProcessInt: Exiting process still alive\n");
  480.     } else {
  481.     UNLOCK_MONITOR;
  482.     }
  483.     return(newState);
  484. }
  485.  
  486.  
  487. /*
  488.  *----------------------------------------------------------------------
  489.  *
  490.  * ProcExitProcess --
  491.  *
  492.  *    Internal routine to handle the termination of a process, due
  493.  *    to a normal exit, a signal or because the process state was
  494.  *    inconsistent.  The file system state associated with the process 
  495.  *    is invalidated. Any children of the process will become detatched.
  496.  *
  497.  * Results:
  498.  *    None.
  499.  *
  500.  * Side effects:
  501.  *    The PCB entry for the process is modified to clean-up FS
  502.  *    state. The specified process may be placed on the dead list.
  503.  *      If thisProcess is TRUE, a context switch is performed.  If not,
  504.  *    then the exit is being performed on behalf of another process;
  505.  *     the procPtr comes in locked and is unlocked as a side effect.
  506.  *
  507.  *----------------------------------------------------------------------
  508.  */
  509. void
  510. ProcExitProcess(exitProcPtr, reason, status, code, thisProcess) 
  511.     register Proc_ControlBlock     *exitProcPtr;    /* Exiting process. */
  512.     int             reason;        /* Why the process is dieing: 
  513.                          * EXITED, SIGNALED, 
  514.                          * DESTROYED  */
  515.     int                status;        /* Exit status, signal # or 
  516.                          * destroy status. */
  517.     int             code;        /* Signal sub-status */
  518.     Boolean             thisProcess;    /* TRUE => context switch */
  519. {
  520.     register Boolean         migrated;
  521.     Boolean            noVm;
  522.  
  523.     migrated = (exitProcPtr->genFlags & PROC_FOREIGN);
  524.  
  525.     /*
  526.      * Decrement the reference count on the environment.
  527.      */
  528.  
  529.     if (!migrated && exitProcPtr->environPtr != (Proc_EnvironInfo *) NIL) {
  530.     ProcDecEnvironRefCount(exitProcPtr->environPtr);
  531.     }
  532.  
  533.     /*
  534.      * The process is already locked if it comes in on behalf of someone
  535.      * else.
  536.      */
  537.     if (thisProcess) {
  538.     Proc_Lock(exitProcPtr);
  539.     }
  540.     if (exitProcPtr->genFlags & PROC_NO_VM) {
  541.     noVm = TRUE;
  542.     } else {
  543.     noVm = FALSE;
  544.     exitProcPtr->genFlags |= PROC_NO_VM;
  545.     }
  546.     Proc_Unlock(exitProcPtr);
  547.  
  548.     /*
  549.      * We have to do the Fs_CloseState in two phases:
  550.      *
  551.      * We must close pseudo-devices before destroying vm.
  552.      * Otherwise there is a race (hit by migd) when a pseudo-device
  553.      * is destroyed because data may be sent to the pseudo-device after
  554.      * it loses its vm but before it is removed from the file system.
  555.      * We will then crash because it has no vm for the data.
  556.      *
  557.      * We need to close swap files after deleting all the VM segments.
  558.      * Otherwise we die if a COW segment has swapped-out data.  The
  559.      * problem is we get the data from swap when we delete the segment.
  560.      * Thus we must delete the segment before we close down the swap files.
  561.      * --Ken Shirriff 10/90
  562.      */
  563.  
  564.     if (exitProcPtr->fsPtr != (struct Fs_ProcessState *) NIL) {
  565.     Fs_CloseState(exitProcPtr,0);
  566.     }
  567.  
  568.     /*
  569.      * Free up virtual memory resources, unless they were already freed.
  570.      */
  571.  
  572. #ifdef sun4
  573.     Mach_FlushWindowsToStack();
  574.     VmMach_FlushCurrentContext();
  575. #endif
  576.     if ((exitProcPtr->genFlags & PROC_USER) && !noVm) {
  577.     int i=0;
  578.     while (exitProcPtr->vmPtr->sharedSegs != (List_Links *)NIL) {
  579.  
  580.         if (exitProcPtr->vmPtr->sharedSegs == (List_Links *)NULL) {
  581.         dprintf("ProcExitProcess: warning: sharedSegs == NULL\n");
  582.         break;
  583.         }
  584.           i++;
  585.           if (i>20) {
  586.           dprintf("ProcExitProcess: procExit: segment loop!\n");
  587.           break;
  588.           }
  589.           if (exitProcPtr->vmPtr->sharedSegs==(List_Links *)NULL) {
  590.           printf("ProcExitProcess: Danger: null sharedSegs list\n");
  591.           break;
  592.           }
  593.           if (List_IsEmpty(exitProcPtr->vmPtr->sharedSegs)) {
  594.           printf("ProcExitProcess: Danger: empty sharedSegs list\n");
  595.           break;
  596.           }
  597.           if (List_First(exitProcPtr->vmPtr->sharedSegs)==
  598.               (List_Links *)NULL) {
  599.           break;
  600.           }
  601.           Vm_DeleteSharedSegment(exitProcPtr, (Vm_SegProcList *)
  602.             List_First(exitProcPtr->vmPtr->sharedSegs));
  603.       }
  604.     for (i = VM_CODE; i <= VM_STACK; i++) {
  605.         Vm_SegmentDelete(exitProcPtr->vmPtr->segPtrArray[i], exitProcPtr);
  606.         exitProcPtr->vmPtr->segPtrArray[i] = (Vm_Segment *)NIL;
  607.     }
  608.     }
  609.  
  610.     if (exitProcPtr->fsPtr != (struct Fs_ProcessState *) NIL) {
  611.     Fs_CloseState(exitProcPtr,1);
  612.     }
  613.  
  614.     /*
  615.      * Remove the process from its process family.  (Note, 
  616.      * migrated processes have family information on the home node.)
  617.      */
  618.     if (!migrated) {
  619.     ProcFamilyRemove(exitProcPtr);
  620.     }
  621.  
  622.     /*
  623.      *  The following information is kept in case the parent
  624.      *    calls Proc_Wait to wait for this process to terminate.
  625.      */
  626.  
  627.     exitProcPtr->termReason    = reason;
  628.     exitProcPtr->termStatus    = status;
  629.     exitProcPtr->termCode    = code;
  630.  
  631.     exitProcPtr->state = ExitProcessInt(exitProcPtr, migrated, thisProcess);
  632.  
  633.     Proc_Unlock(exitProcPtr);
  634. }
  635.  
  636.  
  637. /*
  638.  *----------------------------------------------------------------------
  639.  *
  640.  * Proc_Reaper --
  641.  *
  642.  *    Cleans up the state information kept in the PCB for a dead process.
  643.  *    Processes get put on the dead list after they exit and someone has 
  644.  *    called Proc_Wait to wait for them. Detached processes
  645.  *    are put on the dead list when they call Proc_Exit or Proc_ExitInt.
  646.  *
  647.  * Results:
  648.  *    None.
  649.  *
  650.  * Side effects:
  651.  *    Virtual memory state for processes on the list is deallocated.
  652.  *
  653.  *----------------------------------------------------------------------
  654.  */
  655.  
  656. /* ARGSUSED */
  657. ENTRY void
  658. Proc_Reaper(data, callInfoPtr)
  659.     ClientData                data;        /* procPtr */
  660.     Proc_CallInfo            *callInfoPtr;
  661. {
  662.     register    Proc_ControlBlock     *procPtr = (Proc_ControlBlock *) data;
  663.     LOCK_MONITOR;
  664.     /*
  665.      * On a multiprocess there are two cases where we can't reap the process
  666.      * right away.  1 - the dying process may not have context switched
  667.      * into the DEAD state.  2 - the dying process's kernel stack may
  668.      * be used by a processor in the IdleLoop().  In either of these
  669.      * cases we reschedule ourselves for a second later.
  670.      */
  671.     if ((procPtr->state != PROC_DEAD) ||
  672.     (procPtr->schedFlags & SCHED_STACK_IN_USE)) {
  673.     callInfoPtr->interval = timer_IntOneSecond;
  674.     UNLOCK_MONITOR;
  675.     return;
  676.     } else {
  677.     callInfoPtr->interval = 0;
  678.     }
  679. #ifdef notdef
  680.     /*
  681.      * Next wait for the process's stack to become free.  On a multiprocessor
  682.      * a DEAD processes stack may be used to field interrupt by a processor
  683.      * until another process becomes ready.
  684.      */
  685.     while (procPtr->schedFlags & SCHED_STACK_IN_USE) {
  686.     UNLOCK_MONITOR;
  687.     Sync_WaitTime(time_OneSecond);
  688.     LOCK_MONITOR;
  689.     }
  690.     /*
  691.      * Since the SCHED_STACK_IN_USE is removed from a process before the
  692.      * context switch from that processor occurs we need to syncronize 
  693.      * with the scheduler.  Context switching on to the READY queue will
  694.      * cause such a syncronization.
  695.      */
  696.     Sched_ContextSwitch(PROC_READY);
  697. #endif
  698.     /*
  699.      * At this point a migrated process is not in the PROC_MIGRATED
  700.      * state since it's been moved to the PROC_DEAD state.  
  701.      * Migrated processes don't have a local machine-dependent state
  702.      * hanging off them.  They also don't have a current context, but
  703.      * VmMach_FreeContext can handle that.
  704.      */
  705.     if (procPtr->machStatePtr != (Mach_State *) NIL) {
  706.     Mach_FreeState(procPtr);
  707.     }
  708.     VmMach_FreeContext(procPtr);
  709.  
  710.     ProcFreePCB(procPtr);
  711.  
  712.     UNLOCK_MONITOR;
  713. }
  714.  
  715.  
  716. /*
  717.  *----------------------------------------------------------------------
  718.  *
  719.  * Proc_DetachInt --
  720.  *
  721.  *    The given process is detached from its parent.
  722.  *
  723.  * Results:
  724.  *    SUCCESS            - always returned.
  725.  *
  726.  * Side effects:
  727.  *    PROC_DETACHED flags set in the exitFlags field for the process.
  728.  *
  729.  *----------------------------------------------------------------------
  730.  */
  731.  
  732. ENTRY void
  733. Proc_DetachInt(procPtr)
  734.     register    Proc_ControlBlock    *procPtr;
  735. {
  736.     Proc_ControlBlock     *parentProcPtr;
  737.  
  738.     LOCK_MONITOR;
  739.  
  740.     /*
  741.      * If the process is already detached, there's no point to do it again.
  742.      * The process became detached by calling this routine or its parent
  743.      * has died.
  744.      */
  745.  
  746.     if (procPtr->exitFlags & PROC_DETACHED) {
  747.     UNLOCK_MONITOR;
  748.     return;
  749.     }
  750.  
  751.     procPtr->exitFlags |= PROC_DETACHED;
  752.  
  753.     /*
  754.      *  Wake up the parent in case it has called Proc_Wait to
  755.      *  wait for this child (or any other children) to terminate.
  756.      */
  757.  
  758.     parentProcPtr = Proc_GetPCB(procPtr->parentID);
  759.  
  760.     if (parentProcPtr->state == PROC_MIGRATED) {
  761.     WakeupMigratedParent(parentProcPtr->processID);
  762.     } else {
  763.     Sync_Broadcast(&parentProcPtr->waitCondition);
  764. #ifdef notdef
  765.     SIGNAL_PARENT(parentProcPtr, "Proc_DetachInt");
  766. #endif
  767.     }
  768.     /*
  769.      * Signal the parent later on, when not holding the exit monitor
  770.      * lock.
  771.      */
  772.     Proc_CallFunc(SendSigChild, (ClientData)parentProcPtr->processID, 0);
  773.  
  774.     UNLOCK_MONITOR;
  775. }
  776.  
  777.  
  778. /*
  779.  *----------------------------------------------------------------------
  780.  *
  781.  * Proc_InformParent --
  782.  *
  783.  *    Tell the parent of the given process that the process has changed
  784.  *    state.
  785.  *
  786.  * Results:
  787.  *    None.
  788.  *
  789.  * Side effects:
  790.  *    Status bit set in the exit flags.
  791.  *
  792.  *----------------------------------------------------------------------
  793.  */
  794. ENTRY void
  795. Proc_InformParent(procPtr, childStatus)
  796.     register Proc_ControlBlock    *procPtr;    /* Process whose parent to
  797.                          * inform of state change. */
  798.     int                childStatus;    /* PROC_SUSPEND_STATUS |
  799.                          * PROC_RESUME_STATUS */
  800. {
  801.     Proc_ControlBlock     *parentProcPtr;
  802.     Boolean migrated = FALSE;
  803.  
  804.     LOCK_MONITOR;
  805.  
  806.     /*
  807.      * If the process is already detached, then there is no parent to tell.
  808.      */
  809.     if (procPtr->exitFlags & PROC_DETACHED) {
  810.     UNLOCK_MONITOR;
  811.     return;
  812.     }
  813.  
  814.     /*
  815.      * Wake up the parent in case it has called Proc_Wait to
  816.      * wait for this child (or any other children) to terminate.  Also
  817.      * clear the suspended and waited on flag.
  818.      *
  819.      * For a migrated process, just send a signal no matter what, since it
  820.      * can go to an arbitrary node.  Also, do RPC's using a callback so
  821.      * the monitor lock isn't held during the RPC.  
  822.      */
  823.  
  824.     if (procPtr->genFlags & PROC_FOREIGN) {
  825.     migrated = TRUE;
  826.     }
  827.     if (!migrated) {
  828.     parentProcPtr = Proc_GetPCB(procPtr->parentID);
  829.     Sync_Broadcast(&parentProcPtr->waitCondition);
  830.     }
  831.     Proc_CallFunc(SendSigChild, (ClientData)procPtr->parentID, 0);
  832.     procPtr->exitFlags &= ~PROC_STATUSES;
  833.     procPtr->exitFlags |= childStatus;
  834.  
  835.     UNLOCK_MONITOR;
  836. }
  837.  
  838.  
  839. /*
  840.  *----------------------------------------------------------------------
  841.  *
  842.  * SendSigChild --
  843.  *
  844.  *    Send a SIG_CHILD signal to the given process.
  845.  *
  846.  * Results:
  847.  *    None.
  848.  *
  849.  * Side effects:
  850.  *    None.
  851.  *
  852.  *----------------------------------------------------------------------
  853.  */
  854.  
  855. /* ARGSUSED */
  856. static void
  857. SendSigChild(data, callInfoPtr)
  858.     ClientData        data;
  859.     Proc_CallInfo    *callInfoPtr;    /* passed in by callback routine */
  860. {
  861.     (void)Sig_Send(SIG_CHILD, SIG_NO_CODE, (Proc_PID)data, FALSE, (Address)0);
  862. }
  863.  
  864.  
  865. /*
  866.  *----------------------------------------------------------------------
  867.  *
  868.  * Proc_Detach --
  869.  *
  870.  *    The current process is detached from its parent. Proc_DetachInt called
  871.  *    to do most work.
  872.  *
  873.  * Results:
  874.  *    SUCCESS            - always returned.
  875.  *
  876.  * Side effects:
  877.  *    Statuses set in the proc table for the process.
  878.  *
  879.  *----------------------------------------------------------------------
  880.  */
  881.  
  882. ReturnStatus
  883. Proc_Detach(status)
  884.     int    status;        /* Detach status from caller. */
  885. {
  886.     register    Proc_ControlBlock     *procPtr;
  887.  
  888.     procPtr = Proc_GetEffectiveProc();
  889.     if (procPtr == (Proc_ControlBlock *) NIL) {
  890.     panic("Proc_Detach: procPtr == NIL\n");
  891.     }
  892.  
  893.     /*
  894.      *  The following information is kept in case the parent does a
  895.      *    Proc_Wait on this process.
  896.      */
  897.  
  898.     procPtr->termReason    = PROC_TERM_DETACHED;
  899.     procPtr->termStatus    = status;
  900.     procPtr->termCode    = 0;
  901.  
  902.     Proc_DetachInt(procPtr);
  903.  
  904.     return(SUCCESS);
  905. }
  906.  
  907. static ReturnStatus     CheckPidArray _ARGS_((Proc_ControlBlock *curProcPtr,
  908.                 Boolean returnSuspend, int numPids,
  909.                 Proc_PID *pidArray, 
  910.                 Proc_ControlBlock **procPtrPtr));
  911. static ReturnStatus     LookForAnyChild _ARGS_((Proc_ControlBlock *curProcPtr,
  912.                 Boolean returnSuspend, 
  913.                 Proc_ControlBlock **procPtrPtr));
  914. extern ReturnStatus     DoWait _ARGS_((Proc_ControlBlock *curProcPtr,
  915.                 int    flags, int numPids, Proc_PID *newPidArray,
  916.                 ProcChildInfo *childInfoPtr));
  917.  
  918.  
  919. /*
  920.  *----------------------------------------------------------------------
  921.  *
  922.  * Proc_Wait --
  923.  *
  924.  *    Returns information about a child process that has changed state to
  925.  *    one of terminated, detached, suspended or running.  If the 
  926.  *    PROC_WAIT_FOR_SUSPEND flag is not set then info is only returned about
  927.  *    terminated and detached processes.  If the PROC_WAIT_BLOCK flag is
  928.  *    set then this function will wait for a child process to change state.
  929.  *
  930.  *    A terminated process is a process that has ceased execution because
  931.  *    it voluntarily called Proc_Exit or was involuntarily killed by 
  932.  *    a signal or was destroyed by the kernel due to an invalid stack. 
  933.  *    A detached process is process that has called Proc_Detach to detach 
  934.  *    itself from its parent. It continues to execute until it terminates.
  935.  *
  936.  * Results:
  937.  *    PROC_INVALID_PID -    a process ID in the pidArray was invalid.
  938.  *    SYS_INVALID_ARG -    the numPids argument specified a negative
  939.  *                number of pids in pidArray, or numPids
  940.  *                valid but pidArray was USER_NIL
  941.  *    SYS_ARG_NOACCESS -    an out parameter was inaccessible or
  942.  *                pidArray was inaccessible.
  943.  *
  944.  * Side effects:
  945.  *    Processes may be put onto the dead list after they have been waited on.
  946.  *
  947.  *----------------------------------------------------------------------
  948.  */
  949. ReturnStatus
  950. Proc_Wait(numPids, pidArray, flags, procIDPtr, reasonPtr, 
  951.       statusPtr, subStatusPtr, usagePtr)
  952.     int         numPids;    /* Number of entries in pidArray.  
  953.                       * 0 means wait for any child. */
  954.     Proc_PID         pidArray[];     /* Array of IDs of children to wait 
  955.                      * for. */
  956.     int         flags;        /* PROC_WAIT_BLOCK => wait if no 
  957.                      * children have exited, detached or
  958.                      * suspended.  
  959.                      * PROC_WAIT_FOR_SUSPEND => return 
  960.                      * status of suspended children. */
  961.  
  962.                 /* The following parameters may be USER_NIL. */
  963.     Proc_PID         *procIDPtr;     /* ID of the process that terminated. */
  964.     int         *reasonPtr;    /* Reason why the process exited. */
  965.     int         *statusPtr;    /* Exit status or termination signal 
  966.                      * number.  */
  967.     int         *subStatusPtr;    /* Additional signal status if the 
  968.                      * process died because of a signal. */
  969.     Proc_ResUsage    *usagePtr;    /* Resource usage summary for the 
  970.                      * process and its descendents. */
  971.  
  972. {
  973.     register Proc_ControlBlock     *curProcPtr;
  974.     ReturnStatus        status;
  975.     Proc_PID             *newPidArray = (Proc_PID *) NIL;
  976.     int             newPidSize;
  977.     ProcChildInfo        childInfo;
  978.     Proc_ResUsage         resUsage;
  979.     Boolean            migrated = FALSE;
  980.  
  981.     curProcPtr = Proc_GetCurrentProc();
  982.     if (curProcPtr == (Proc_ControlBlock *) NIL) {
  983.     panic("Proc_Wait: curProcPtr == NIL.\n");
  984.     }
  985.  
  986.     if (curProcPtr->genFlags & PROC_FOREIGN) {
  987.     migrated = TRUE;
  988.     }
  989.     
  990.     /*
  991.      *  If a list of pids to check was given, use it, otherwise
  992.      *  look for any child that has changed state.
  993.      */
  994.     if (numPids < 0) {
  995.     return(SYS_INVALID_ARG);
  996.     } else if (numPids > 0) {
  997.     if (pidArray == USER_NIL) {
  998.         return(SYS_INVALID_ARG);
  999.     } else {
  1000.         /*
  1001.          *  If pidArray is used, make it accessible. Also make sure that
  1002.          *  the pids are in the proper range.
  1003.          */
  1004.         newPidSize = numPids * sizeof(Proc_PID);
  1005.         newPidArray = (Proc_PID *) malloc(newPidSize);
  1006.         status = Vm_CopyIn(newPidSize, (Address) pidArray,
  1007.                    (Address) newPidArray);
  1008.         if (status != SUCCESS) {
  1009.         free((Address) newPidArray);
  1010.         return(SYS_ARG_NOACCESS);
  1011.         }
  1012.     }
  1013.     }
  1014.  
  1015.     if (!migrated) {
  1016.     status = DoWait(curProcPtr, flags, numPids, newPidArray, &childInfo);
  1017.     } else {
  1018.     status = ProcRemoteWait(curProcPtr, flags, numPids, newPidArray,
  1019.                 &childInfo);
  1020.     }
  1021.  
  1022.     if (numPids > 0) {
  1023.     free((Address) newPidArray);
  1024.     }
  1025.  
  1026.     if (status == SUCCESS) {
  1027.     if (procIDPtr != USER_NIL) {
  1028.         if (Vm_CopyOut(sizeof(Proc_PID), (Address) &childInfo.processID, 
  1029.         (Address) procIDPtr) != SUCCESS) {
  1030.         status = SYS_ARG_NOACCESS;
  1031.         }
  1032.     }
  1033.     if (reasonPtr != USER_NIL) {
  1034.         if (Vm_CopyOut(sizeof(int), (Address) &childInfo.termReason, 
  1035.         (Address) reasonPtr) != SUCCESS) {
  1036.         status = SYS_ARG_NOACCESS;
  1037.         }
  1038.     }
  1039.     if (statusPtr != USER_NIL) {
  1040.         if (Vm_CopyOut(sizeof(int), (Address) &childInfo.termStatus, 
  1041.         (Address) statusPtr) != SUCCESS) {
  1042.         status = SYS_ARG_NOACCESS;
  1043.         }
  1044.     }
  1045.     if (subStatusPtr != USER_NIL) {
  1046.         if (Vm_CopyOut(sizeof(int), (Address) &childInfo.termCode, 
  1047.         (Address) subStatusPtr) != SUCCESS) {
  1048.         status = SYS_ARG_NOACCESS;
  1049.         }
  1050.     }
  1051.     if (usagePtr != USER_NIL) {
  1052.         /*
  1053.          * Convert the usages from the internal Timer_Ticks format
  1054.          * into the external Time format.
  1055.          */
  1056.         Timer_TicksToTime(childInfo.kernelCpuUsage,
  1057.                   &resUsage.kernelCpuUsage);
  1058.         Timer_TicksToTime(childInfo.userCpuUsage,
  1059.                   &resUsage.userCpuUsage);
  1060.         Timer_TicksToTime(childInfo.childKernelCpuUsage, 
  1061.                   &resUsage.childKernelCpuUsage);
  1062.         Timer_TicksToTime(childInfo.childUserCpuUsage,
  1063.                   &resUsage.childUserCpuUsage);
  1064.         resUsage.numQuantumEnds = childInfo.numQuantumEnds;
  1065.         resUsage.numWaitEvents = childInfo.numWaitEvents;
  1066.         if (Vm_CopyOut(sizeof(Proc_ResUsage), (Address) &resUsage, 
  1067.                (Address) usagePtr) != SUCCESS) {
  1068.         status = SYS_ARG_NOACCESS;
  1069.         }
  1070.     }
  1071.     }
  1072.  
  1073.     return(status);
  1074. }
  1075.  
  1076.  
  1077. /*
  1078.  *----------------------------------------------------------------------
  1079.  *
  1080.  * DoWait --
  1081.  *
  1082.  *    Execute monitor level code for a Proc_Wait.  Return the information
  1083.  *    about the child that was found if any. 
  1084.  *
  1085.  * Results:
  1086.  *    PROC_INVALID_PID -    a process ID in the pidArray was invalid.
  1087.  *
  1088.  * Side effects:
  1089.  *    None.
  1090.  *
  1091.  *----------------------------------------------------------------------
  1092.  */
  1093.  
  1094. ENTRY ReturnStatus 
  1095. DoWait(curProcPtr, flags, numPids, newPidArray, childInfoPtr)
  1096.     register    Proc_ControlBlock    *curProcPtr;    /* Parent process. */
  1097.             /* PROC_WAIT_BLOCK => wait if no children have changed
  1098.              *               state.
  1099.              * PROC_WAIT_FOR_SUSPEND => return status of suspended
  1100.              *                children. */
  1101.     int                 flags;    
  1102.     int                    numPids;    /* Number of pids in
  1103.                              * newPidArray. */
  1104.     Proc_PID                 *newPidArray;    /* Array of pids. */
  1105.     ProcChildInfo            *childInfoPtr;    /* Place to store child
  1106.                              * information. */
  1107. {
  1108.     ReturnStatus    status;
  1109.  
  1110.     LOCK_MONITOR;
  1111.  
  1112.     while (TRUE) {
  1113.     /*
  1114.      * If a pid array was given, check the array to see if someone on it
  1115.      * has changed state. Otherwise, see if any child has done so.
  1116.      */
  1117.     status = FindExitingChild(curProcPtr, flags & PROC_WAIT_FOR_SUSPEND,
  1118.                 numPids, newPidArray, childInfoPtr);
  1119.  
  1120.     /* 
  1121.      * If someone was found or there was an error, break out of the loop
  1122.      * because we are done. FAILURE means no one was found.
  1123.      */
  1124.     if (status != FAILURE) {
  1125.         break;
  1126.     }
  1127.  
  1128.     /*
  1129.      *  If the search doesn't yields a child, we go to sleep waiting 
  1130.      *  for a process to wake us up if it exits or detaches itself.
  1131.      */
  1132.     if (!(flags & PROC_WAIT_BLOCK)) {
  1133.         /*
  1134.          * Didn't find anyone to report on.
  1135.          */
  1136.         status = PROC_NO_EXITS;
  1137.         break;
  1138.  
  1139.     } else {    
  1140.         /*
  1141.          *  Since the current process is local, it will go to sleep
  1142.          *  on its waitCondition.  A child will wakeup the process by
  1143.          *  doing a wakeup on its parent's waitCondition.
  1144.          *
  1145.          *  This technique reduces the number of woken processes
  1146.          *  compared to having every process wait on the same
  1147.          *  event (e.g. exiting list address) when it goes to
  1148.          *  sleep.  When we wake up, the search will start again.
  1149.          *
  1150.          * Check for the signal being SIG_CHILD, in which case
  1151.          * don't abort the Proc_Wait.  This can happen if the parent and
  1152.          * the child are on different hosts so the Sync_Wait is aborted
  1153.          * by the signal rather than a wakeup.  (The parent should handle
  1154.          * SIGCHLD better, but it might not, thereby missing the child's
  1155.          * change in state.)
  1156.          */
  1157.         if (Sync_Wait(&curProcPtr->waitCondition, TRUE)) {
  1158.         if (Sig_Pending(curProcPtr) != (1 << (SIG_CHILD - 1))) {
  1159.             status = GEN_ABORTED_BY_SIGNAL;
  1160.             break;
  1161.         }
  1162.         }
  1163.     }
  1164.     }
  1165.  
  1166.     UNLOCK_MONITOR;
  1167.     return(status);
  1168. }
  1169.  
  1170.  
  1171. /*
  1172.  * ----------------------------------------------------------------------------
  1173.  *
  1174.  * ProcRemoteWait --
  1175.  *
  1176.  *    Perform an RPC to do a Proc_Wait on the home node of the given
  1177.  *    process.  Transfer the information for a child that has changed state,
  1178.  *    if one exists, and set up the information for a remote
  1179.  *    wait if the process wishes to block waiting for a child.  Note
  1180.  *    that this routine is unsynchronized, since monitor locking is
  1181.  *    performed on the home machine of the process.
  1182.  *
  1183.  * Results:
  1184.  *    The status from the remote Proc_Wait (or RPC status) is returned.
  1185.  *
  1186.  * Side effects:
  1187.  *    None.
  1188.  *
  1189.  * ----------------------------------------------------------------------------
  1190.  */
  1191.  
  1192. ReturnStatus
  1193. ProcRemoteWait(procPtr, flags, numPids, pidArray, childInfoPtr)
  1194.     Proc_ControlBlock    *procPtr;
  1195.     int            flags;
  1196.     int            numPids;
  1197.     Proc_PID        pidArray[];
  1198.     ProcChildInfo    *childInfoPtr;
  1199. {
  1200.     ProcRemoteWaitCmd cmd;
  1201.     Rpc_Storage storage;
  1202.     ReturnStatus status;
  1203.     int numTries;
  1204.  
  1205.     if (proc_MigDebugLevel > 3) {
  1206.     printf("ProcRemoteWait(%x, ...) called.\n", procPtr->processID);
  1207.     }
  1208.  
  1209.     /*
  1210.      * Check to make sure the home node is up, and kill the process if
  1211.      * it isn't.  The call to exit never returns.
  1212.      */
  1213.     status = Recov_IsHostDown(procPtr->peerHostID);
  1214.     if (status != SUCCESS) {
  1215.     if (proc_MigDebugLevel > 0) {
  1216.         printf("Proc_DoRemoteCall: host %d is down; killing process %x.\n",
  1217.                procPtr->peerHostID, procPtr->processID);
  1218.     }
  1219.     Proc_ExitInt(PROC_TERM_DESTROYED, (int) PROC_NO_PEER, 0);
  1220.     /*
  1221.      * This point should not be reached, but the N-O-T-R-E-A-C-H-E-D
  1222.      * directive causes a complaint when there's code after it.
  1223.      */
  1224.     panic("ProcRemoteWait: Proc_ExitInt returned.\n");
  1225.     return(PROC_NO_PEER);
  1226.     }
  1227.     /*
  1228.      * Set up the invariant fields of the rpc call, since we may make
  1229.      * multiple calls after waiting.
  1230.      */
  1231.     
  1232.     cmd.pid = procPtr->peerProcessID;
  1233.     cmd.numPids = numPids;
  1234.     cmd.flags = flags;
  1235.     cmd.token = NIL;
  1236.  
  1237.     storage.requestParamPtr = (Address) &cmd;
  1238.     storage.requestParamSize = sizeof(ProcRemoteWaitCmd);
  1239.     storage.requestDataPtr = (Address) pidArray;
  1240.     storage.requestDataSize = numPids * sizeof(Proc_PID);
  1241.  
  1242.     while (TRUE) {
  1243.  
  1244.     storage.replyParamPtr = (Address) NIL;
  1245.     storage.replyParamSize = 0;
  1246.     storage.replyDataPtr = (Address) childInfoPtr;
  1247.     storage.replyDataSize = sizeof(ProcChildInfo);
  1248.  
  1249.     if (flags & PROC_WAIT_BLOCK) {
  1250.         Sync_GetWaitToken((Proc_PID *) NIL, &cmd.token);
  1251.     }
  1252.  
  1253.     /*
  1254.      * Set up for the RPC.
  1255.      */
  1256.     
  1257.     for (numTries = 0; numTries < PROC_MAX_RPC_RETRIES; numTries++) {
  1258.         status = Rpc_Call(procPtr->peerHostID, RPC_PROC_REMOTE_WAIT,
  1259.                   &storage);
  1260.         if (status != RPC_TIMEOUT) {
  1261.         break;
  1262.         }
  1263.         status = Proc_WaitForHost(procPtr->peerHostID);
  1264.         if (status != SUCCESS) {
  1265.         break;
  1266.         }
  1267.     }
  1268.  
  1269.     /*
  1270.      * If the status is FAILURE, no children have exited so far.  In
  1271.      * this case, we may want to sleep.
  1272.      */
  1273.     if (status != FAILURE) {
  1274.         break;
  1275.     }
  1276.  
  1277.     /*
  1278.      * If the search doesn't yield a child and we are supposed to block,
  1279.      * we go to sleep waiting for a process to wake us up if it
  1280.      * exits or detaches itself.
  1281.      */
  1282.  
  1283.     if (!(flags & PROC_WAIT_BLOCK)) {
  1284.         /*
  1285.          * Didn't find anyone to report on.
  1286.          */
  1287.         status = PROC_NO_EXITS;
  1288.         break;
  1289.  
  1290.     } else if (Sync_ProcWait((Sync_Lock *) NIL, TRUE)) {
  1291.         status = GEN_ABORTED_BY_SIGNAL;
  1292.         break;
  1293.     }  
  1294.     }
  1295.  
  1296.     if (status == PROC_NO_PEER) {
  1297.     (void) Sig_Send(SIG_KILL, (int) PROC_NO_PEER, procPtr->processID,
  1298.             FALSE, (Address)0); 
  1299.     if (proc_MigDebugLevel > 1) {
  1300.         printf("ProcRemoteWait killing process %x: home node's copy died.\n",
  1301.            procPtr->processID);
  1302.     }
  1303.     } else if (proc_MigDebugLevel > 3) {
  1304.     printf("ProcRemoteWait returning status %x.\n", status);
  1305.     if (status == SUCCESS && proc_MigDebugLevel > 6) {
  1306.         printf("Child's id is %x, status %x.\n",
  1307.                childInfoPtr->processID, childInfoPtr->termStatus);
  1308.     }
  1309.     }
  1310.     return(status);
  1311. }
  1312.  
  1313.  
  1314. /*
  1315.  *----------------------------------------------------------------------
  1316.  *
  1317.  * ProcServiceRemoteWait --
  1318.  *
  1319.  *    Services the Proc_Wait command for a migrated process.  If
  1320.  *    there is an appropriate child, returns information about it (refer
  1321.  *    to Proc_Wait).  If not, returns    PROC_NO_EXITS.  If the migrated
  1322.  *    process specified that it should block, set up a remote wakeup
  1323.  *    for when a child changes state.
  1324.  *
  1325.  * Results:
  1326.  *    PROC_INVALID_PID -    a process ID in the pidArray is invalid.
  1327.  *    PROC_NO_EXITS    -    no children have changed state which have
  1328.  *                not already been waited upon.
  1329.  *
  1330.  * Side effects:
  1331.  *    Processes on the exiting list may be put on the dead list after 
  1332.  *    they have been waited on.  A remote wakeup may be established.
  1333.  *
  1334.  *----------------------------------------------------------------------
  1335.  */
  1336.  
  1337. ENTRY ReturnStatus
  1338. ProcServiceRemoteWait(curProcPtr, flags, numPids, pidArray, waitToken,
  1339.               childInfoPtr)
  1340.     register Proc_ControlBlock     *curProcPtr;
  1341.     int                flags;
  1342.     int numPids;    /* Number of entries in pidArray.  
  1343.              *  0 means wait for any child. */
  1344.     Proc_PID pidArray[]; /* Array of IDs of children to wait for. */
  1345.     int waitToken;      /* Token to use if blocking. */
  1346.     ProcChildInfo *childInfoPtr; /* Information to return about child. */
  1347.  
  1348. {
  1349.     ReturnStatus        status;
  1350.  
  1351.     LOCK_MONITOR;
  1352.  
  1353.     status = FindExitingChild(curProcPtr, flags & PROC_WAIT_FOR_SUSPEND,
  1354.                 numPids, pidArray, childInfoPtr);
  1355.     if (proc_MigDebugLevel > 3) {
  1356.     printf("pid %x got status %x from FindExitingChild\n",
  1357.            curProcPtr->processID, status);
  1358.     if (status == SUCCESS && proc_MigDebugLevel > 6) {
  1359.         printf("Child's id is %x, status %x.\n",
  1360.                childInfoPtr->processID, childInfoPtr->termStatus);
  1361.     }
  1362.     }
  1363.  
  1364.     /* 
  1365.      * FAILURE means no one was found, so set up a remote wakeup if needed.
  1366.      * Otherwise, just return the childInfo as it was set by FindExitingChild
  1367.      * and get out.
  1368.      */
  1369.     if (status == FAILURE) {
  1370.     if (flags & PROC_WAIT_BLOCK) {
  1371.         Sync_SetWaitToken(curProcPtr, waitToken);
  1372.     }
  1373.     } 
  1374.  
  1375.     UNLOCK_MONITOR;
  1376.     return(status);
  1377. }
  1378.  
  1379.  
  1380. /*
  1381.  *----------------------------------------------------------------------
  1382.  *
  1383.  *  FindExitingChild --
  1384.  *
  1385.  *    Find a child of the specified process who has changed state,
  1386.  *    subject to possible constraints (a list of process
  1387.  *    IDs to check).  If a process is found, send that process to the
  1388.  *    reaper if appropriate.
  1389.  *
  1390.  *    If numPids is 0, look for any child, else look for specific
  1391.  *    processes.
  1392.  *
  1393.  * Results:
  1394.  *    PROC_NO_CHILDREN -    There are no children of this process left
  1395.  *                to be waited on.
  1396.  *    FAILURE -        didn't find any child of interest.
  1397.  *    SUCCESS -        got one.
  1398.  *
  1399.  * Side effects:
  1400.  *    If a process is found, *childInfoPtr is set to contain the relevant
  1401.  *    information from the child.
  1402.  *
  1403.  *----------------------------------------------------------------------
  1404.  */
  1405.  
  1406. INTERNAL static ReturnStatus 
  1407. FindExitingChild(parentProcPtr, returnSuspend, numPids, pidArray, infoPtr)
  1408.     Proc_ControlBlock         *parentProcPtr;    /* Parent's PCB */
  1409.     Boolean            returnSuspend;    /* Return information about
  1410.                          * suspended or resumed
  1411.                          * children. */ 
  1412.     int             numPids;    /* Number of Pids in pidArray */
  1413.     Proc_PID             *pidArray;    /* Array of Pids to check */
  1414.     register ProcChildInfo    *infoPtr;    /* Place to return info */
  1415. {
  1416.     ReturnStatus status;
  1417.     Proc_ControlBlock *paramProcPtr;
  1418.     register Proc_ControlBlock *procPtr;
  1419.     
  1420.     if (numPids > 0) {
  1421.     status = CheckPidArray(parentProcPtr, returnSuspend, numPids, pidArray,
  1422.                    ¶mProcPtr);
  1423.     } else {
  1424.     status = LookForAnyChild(parentProcPtr, returnSuspend, ¶mProcPtr);
  1425.     }
  1426.     if (status == SUCCESS) {
  1427.     procPtr = paramProcPtr;
  1428.     if (procPtr->state == PROC_EXITING ||
  1429.         (procPtr->exitFlags & PROC_DETACHED)) {
  1430.         List_Remove((List_Links *) &(procPtr->siblingElement));
  1431.         infoPtr->termReason        = procPtr->termReason;
  1432.         if (procPtr->state == PROC_EXITING) {
  1433.         /*
  1434.          * Once an exiting process has been waited on it is moved
  1435.          * from the exiting state to the dead state.
  1436.          */
  1437.         procPtr->state = PROC_DEAD;
  1438.         Proc_CallFunc(Proc_Reaper,  (ClientData) procPtr, 0);
  1439.         } else {
  1440.         /*
  1441.          * The child is detached and running.  Set a flag to make sure
  1442.          * we don't find this process again in a future call to
  1443.          * Proc_Wait.
  1444.          */
  1445.         procPtr->exitFlags |= PROC_WAITED_ON;
  1446.         }
  1447.     } else {
  1448.         /*
  1449.          * The child was suspended or resumed.
  1450.          */
  1451.         if (procPtr->exitFlags & PROC_SUSPEND_STATUS) {
  1452.         procPtr->exitFlags &= ~PROC_SUSPEND_STATUS;
  1453.         infoPtr->termReason = PROC_TERM_SUSPENDED;
  1454.         } else if (procPtr->exitFlags & PROC_RESUME_STATUS) {
  1455.         procPtr->exitFlags &= ~PROC_RESUME_STATUS;
  1456.         infoPtr->termReason = PROC_TERM_RESUMED;
  1457.         }
  1458.     }
  1459.  
  1460.     infoPtr->processID        = procPtr->processID;
  1461.     infoPtr->termStatus        = procPtr->termStatus;
  1462.     infoPtr->termCode        = procPtr->termCode;
  1463.     infoPtr->kernelCpuUsage        = procPtr->kernelCpuUsage.ticks;
  1464.     infoPtr->userCpuUsage        = procPtr->userCpuUsage.ticks;
  1465.     infoPtr->childKernelCpuUsage    = procPtr->childKernelCpuUsage.ticks;
  1466.     infoPtr->childUserCpuUsage     = procPtr->childUserCpuUsage.ticks;
  1467.     infoPtr->numQuantumEnds        = procPtr->numQuantumEnds;
  1468.     infoPtr->numWaitEvents        = procPtr->numWaitEvents;
  1469.  
  1470.     Proc_Unlock(procPtr);
  1471.     }
  1472.  
  1473.     return(status);
  1474. }              
  1475.  
  1476.  
  1477. /*
  1478.  *----------------------------------------------------------------------
  1479.  *
  1480.  *  LookForAnyChild --
  1481.  *
  1482.  *    Search the process's list of children to see if any of 
  1483.  *    them have exited, become detached or been suspended or resumed.
  1484.  *    If no child is found, make sure there is a child who can wake us up.
  1485.  *
  1486.  * Results:
  1487.  *    PROC_NO_CHILDREN -    There are no children of this process left
  1488.  *                to be waited on.
  1489.  *    FAILURE -        didn't find any child of interest.
  1490.  *    SUCCESS -        got one.
  1491.  *
  1492.  * Side effects:
  1493.  *    None.
  1494.  *
  1495.  *----------------------------------------------------------------------
  1496.  */
  1497.  
  1498. INTERNAL static ReturnStatus
  1499. LookForAnyChild(curProcPtr, returnSuspend, procPtrPtr)
  1500.     register    Proc_ControlBlock    *curProcPtr;    /* Parent proc.*/
  1501.     Boolean                returnSuspend;    /* Return info about
  1502.                              * suspended children.*/    Proc_ControlBlock             **procPtrPtr;    /* Child proc. */
  1503. {
  1504.     register Proc_ControlBlock *procPtr;
  1505.     register Proc_PCBLink *procLinkPtr;
  1506.     Boolean foundValidChild = FALSE;
  1507.  
  1508.     /*
  1509.      *  Loop through the list of children, looking for the first child
  1510.      *  to have changed state. Ignore children that are detached
  1511.      *  and waited-on.
  1512.      */
  1513.  
  1514.     LIST_FORALL((List_Links *) curProcPtr->childList,
  1515.         (List_Links *) procLinkPtr) {
  1516.         procPtr = procLinkPtr->procPtr;
  1517.     /*
  1518.      *  It may be that one of our children is in the process of exiting.
  1519.      *  If it is marked as 'dying' but not 'exiting', then it has
  1520.      *  left the monitor (obvious because we're in the monitor now)
  1521.      *  but hasn't completed the context switch to the 'exiting' state.
  1522.      *  This can only happen if the child is on a different processor
  1523.      *  from ourself.  We'll wait for the child to become exiting since
  1524.      *  it will take at most the length of a context switch to finish.
  1525.      *  If we don't wait for this child we will miss the transition
  1526.      *  and potentially wait forever.
  1527.      */
  1528.     if (procPtr->genFlags & PROC_DYING) {
  1529.         while (procPtr->state != PROC_EXITING) {
  1530.         /*
  1531.          * Wait for the other processor to set the state to exiting.
  1532.          */
  1533.         }
  1534.     }
  1535.     if ((procPtr->state == PROC_EXITING) ||
  1536.         (procPtr->exitFlags & PROC_DETACHED) ||
  1537.         (returnSuspend && (procPtr->exitFlags & PROC_STATUSES))) {
  1538.         if (!(procPtr->exitFlags & PROC_WAITED_ON)) {
  1539.             *procPtrPtr = procPtr;
  1540.         Proc_Lock(procPtr);
  1541.             return(SUCCESS);
  1542.         }
  1543.     } else {
  1544.         foundValidChild = TRUE;
  1545.     }
  1546.     }
  1547.  
  1548.     if (foundValidChild) {
  1549.     return(FAILURE);
  1550.     }
  1551.     return(PROC_NO_CHILDREN);
  1552. }
  1553.  
  1554.  
  1555. /*
  1556.  *----------------------------------------------------------------------
  1557.  *
  1558.  *  CheckPidArray --
  1559.  *
  1560.  *    Search the process's array of children to see if any of them 
  1561.  *    have exited, become detached or been suspended or resumed.
  1562.  *
  1563.  * Results:
  1564.  *    FAILURE -        didn't find any child of interest.
  1565.  *    PROC_INVALID_PID -    a pid in the array was invalid.
  1566.  *    SUCCESS -        got one.
  1567.  *
  1568.  * Side effects:
  1569.  *    None.
  1570.  *
  1571.  *----------------------------------------------------------------------
  1572.  */
  1573.  
  1574.  
  1575. INTERNAL static ReturnStatus
  1576. CheckPidArray(curProcPtr, returnSuspend, numPids,  pidArray, procPtrPtr)
  1577.     register    Proc_ControlBlock    *curProcPtr;    /* Parent proc. */
  1578.     Boolean                returnSuspend;    /* Return information
  1579.                              * about suspended or
  1580.                              * resumed children. */
  1581.     int                    numPids;    /* Number of pids in 
  1582.                              * pidArray. */
  1583.     Proc_PID                *pidArray;    /* Array of pids to 
  1584.                              * check. */
  1585.     Proc_ControlBlock             **procPtrPtr;    /* Child proc. */
  1586. {
  1587.     register Proc_ControlBlock    *procPtr;
  1588.     int                i;
  1589.  
  1590.     /*
  1591.      * The user has specified a list of processes to wait for.
  1592.      * If a specified process is non-existent or is not a child of the
  1593.      * calling process return an error status.
  1594.      */
  1595.     for (i=0; i < numPids; i++) {
  1596.     procPtr = Proc_LockPID(pidArray[i]);
  1597.     if (procPtr == (Proc_ControlBlock *) NIL) {
  1598.         return(PROC_INVALID_PID);
  1599.     }
  1600.     if (!Proc_ComparePIDs(procPtr->parentID, curProcPtr->processID)) {
  1601.         Proc_Unlock(procPtr);
  1602.         return(PROC_INVALID_PID);
  1603.     }
  1604.     if ((procPtr->state == PROC_EXITING) ||
  1605.         (procPtr->exitFlags & PROC_DETACHED) ||
  1606.         (returnSuspend && (procPtr->exitFlags & PROC_STATUSES))) {
  1607.         if (!(procPtr->exitFlags & PROC_WAITED_ON)) {
  1608.         *procPtrPtr = procPtr;
  1609.         return(SUCCESS);
  1610.         }
  1611.     }
  1612.     Proc_Unlock(procPtr);
  1613.     } 
  1614.     return(FAILURE);
  1615. }
  1616.  
  1617.  
  1618. /*
  1619.  *----------------------------------------------------------------------
  1620.  *
  1621.  * Proc_NotifyMigratedWaiters --
  1622.  *
  1623.  *    Waits to find out about migrated processes that have performed
  1624.  *    Proc_Waits and then issues Sync_RemoteNotify calls to wake them
  1625.  *    up.  Uses a monitored procedure to access the shared list containing
  1626.  *    process IDs.
  1627.  *
  1628.  * Results:
  1629.  *    None.
  1630.  *
  1631.  * Side effects:
  1632.  *    RPCs are issued as children of migrated processes detach or die.
  1633.  *
  1634.  *----------------------------------------------------------------------
  1635.  */
  1636.  
  1637. /* ARGSUSED */
  1638. void
  1639. Proc_NotifyMigratedWaiters(data, callInfoPtr)
  1640.     ClientData        data;            /* pid */
  1641.     Proc_CallInfo    *callInfoPtr;        /* not used */
  1642. {
  1643.     Proc_PID             pid = (Proc_PID) data;
  1644.     register Proc_ControlBlock     *procPtr;
  1645.     Sync_RemoteWaiter         waiter;
  1646.     ReturnStatus         status;
  1647.  
  1648.     procPtr = Proc_LockPID(pid);
  1649.     if (procPtr == (Proc_ControlBlock *) NIL) {
  1650.     return;
  1651.     }
  1652.  
  1653.     waiter.hostID = procPtr->peerHostID;
  1654.     waiter.pid = procPtr->peerProcessID;
  1655.     waiter.waitToken =  procPtr->waitToken;
  1656.     Proc_Unlock(procPtr);
  1657.  
  1658.     if (proc_MigDebugLevel > 3) {
  1659.     printf("Proc_NotifyMigratedWaiters: notifying process %x.\n",
  1660.            waiter.pid);
  1661.     }
  1662.     status = Sync_RemoteNotify(&waiter);
  1663.     if (status != SUCCESS) {
  1664.     printf("Warning: received status %x notifying process.\n", status);
  1665.     }
  1666. }
  1667.  
  1668.  
  1669. /*
  1670.  *----------------------------------------------------------------------
  1671.  *
  1672.  * WakeupMigratedParent --
  1673.  *
  1674.  *    Call the function Proc_NotifyMigratedWaiters by starting a process
  1675.  *    on it.
  1676.  *
  1677.  * Results:
  1678.  *    None.
  1679.  *
  1680.  * Side effects:
  1681.  *    None.
  1682.  *
  1683.  *----------------------------------------------------------------------
  1684.  */
  1685.  
  1686. static INTERNAL void
  1687. WakeupMigratedParent(pid)
  1688.     Proc_PID pid;
  1689. {
  1690.  
  1691.     if (proc_MigDebugLevel > 3) {
  1692.     printf("WakeupMigratedParent: inserting process %x.\n", pid);
  1693.     }
  1694.     Proc_CallFunc(Proc_NotifyMigratedWaiters, (ClientData) pid, 0);
  1695. }
  1696.  
  1697.